package com.fingard;

import cn.hutool.core.util.ClassUtil;
import com.fingard.cluster.ClusterCenter;
import com.fingard.crypto.InnerCipher;
import com.fingard.diagnostics.LimitMsg;
import com.fingard.diagnostics.StartLog;
import com.fingard.diagnostics.trace.LogTrace;
import com.fingard.dsp.DSPCenter;
import com.fingard.dsp.Distributor;
import com.fingard.dsp.bank.DynamicClassLoader;
import com.fingard.dsp.bank.directbank.DirectBase;
import com.fingard.dsp.linksecure.CertConfig;
import com.fingard.dsp.localdb.DbInitiator;
import com.fingard.dsp.localdb.LocalDbHelper;
import com.fingard.dsp.localdb.PartitionTable;
import com.fingard.dsp.task.TaskCenter;
import com.fingard.dsp.web.runtime.RuntimeManager;
import com.fingard.luna.framework.base.log.LogUtil;
import com.fingard.net.IpHelper;
import com.fingard.remoting.client.TenantClientServer;
import com.fingard.remoting.server.TenantServer;
import com.fingard.startup.BankServer;
import com.fingard.startup.JavaClassMap;
import com.fingard.text.StringHelper;
import org.slf4j.Logger;

import javax.inject.Singleton;
import java.io.File;
import java.nio.charset.Charset;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;

public class FGBiz {

    private static final Logger logger = LogUtil.getLogger(FGBiz.class);

    public static DSPCenter dspCenter = null;
    public static Distributor distributor = null;

    public static PartitionTable partTable = null;
    public static ClusterCenter clusterCenter = null;

    public static InnerCipher cipher = null;

    public static DynamicClassLoader dynamicClassLoader = null;

    public static void init(String p_mainDir) throws Exception {
        if (dynamicClassLoader == null) {
            String jarFilePath = FGBiz.DSPHOME_Parent + File.separator + "dsp_lib" + File.separator + "directchannel";
            File jarFile = new File(jarFilePath);
            if (!jarFile.exists()) {
                jarFile.mkdirs();
            }
            dynamicClassLoader = new DynamicClassLoader(jarFilePath);
        }
        if (startLog == null) {
            startLog = new StartLog();
        }

        if (limitMsg == null) {
            limitMsg = new LimitMsg();
        }

        try {
            cipher = new InnerCipher();
        } catch (Throwable t) {
            startLog.exception("InnerCipher", t);
        }

        getInitInfo();
        dspCenter = new DSPCenter(p_mainDir);
        if (FGBiz.dspCenter.dspSet.enableEncrypt) {
            FGBiz.startLog.addToLimit("BankServer", "启动转发加密和加密识别功能");
            FGBiz.dspCenter.dspSet.certConfig = new CertConfig().InitCertConfig();
        } else {
            FGBiz.startLog.addToLimit("BankServer", "不启动转发加密和加密识别功能");
        }
        distributor = new Distributor(p_mainDir);
        distributor.init();

    }

    public static void initLocalDb() throws Exception {
        if (!dspCenter.dspSet.disableLocalDB) {
            DbInitiator tmpDbInit = new DbInitiator();
            tmpDbInit.initDb();
            partTable = new PartitionTable();
            Date nowDate = new Date();
            ArrayList<String> teList = FGBiz.dspCenter.getDistinctTenant();
            if (teList.size() > 0) {
                for (int i = 0; i < teList.size(); i++) {
                    String eachTenant = teList.get(i);
                    String dbFileByMonth = FGBiz.dspCenter.dspSet.getLocalDbFileByMonth(eachTenant, nowDate);
                    if (dbFileByMonth == null) {
                        dbFileByMonth = "";
                    }
                    if (StringHelper.hasAnyChar(dbFileByMonth)) {
                        startLog.addLogNoTime("当前分区本地数据库文件：" + dbFileByMonth);
                        Connection initConn = partTable.getLoaclDbConnByPart(eachTenant, nowDate);
                        FGBiz.startLog.addNoConsole("表:");
                        ArrayList<String> tabList = LocalDbHelper.getTableNameList(initConn);
                        FGBiz.startLog.addNoConsole(StringHelper.join("\r\n", tabList));
                        initConn.close();
                    }
                }
            } else {
                String eachTenant = "";
                String dbFileByMonth = FGBiz.dspCenter.dspSet.getLocalDbFileByMonth(eachTenant, nowDate);
                if (dbFileByMonth == null) {
                    dbFileByMonth = "";
                }
                if (StringHelper.hasAnyChar(dbFileByMonth)) {
                    startLog.addLogNoTime("当前分区本地数据库文件：" + dbFileByMonth);
                    Connection initConn = partTable.getLoaclDbConnByPart(eachTenant, nowDate);
                    FGBiz.startLog.addNoConsole("表:");
                    ArrayList<String> tabList = LocalDbHelper.getTableNameList(initConn);
                    FGBiz.startLog.addNoConsole(StringHelper.join("\r\n", tabList));
                    initConn.close();
                }
            }
        } else {
            startLog.addLogNoTime("本地数据库文件被禁用（不推荐）");
        }
    }

    /**
     * 默认字符集
     */
    public static String getDefaultCharset() {
        return dspCenter.dspSet.charsetName;
    }

    /**
     * 取本地文件数据库连接
     *
     * @throws Exception
     */
    public static Connection getLocalDbConn() throws Exception {
        return FGBiz.dspCenter.dspSet.dbLocalConnSet.getConnection();
    }

    /**
     * DSP主目录
     */
    public static String DSPHOME = "";
    public static String DSPHOME_Parent = "";

    public static String localHostIp = "";

    private static void getInitInfo() {

        if (StringHelper.isNullOrEmpty(localHostIp)) {
            localHostIp = IpHelper.getLocalHostIp();
            startLog.addLogNoTime("本机IP：" + localHostIp);
        }

        if (StringHelper.isNullOrEmpty(DSPHOME)) {
            String classPath = ClassUtil.getClassPath();
            DSPHOME = new File(classPath).getParent() + File.separator + "dsp-config";
            if (!new File(DSPHOME).exists()) {
                DSPHOME = System.getProperty("user.dir") + File.separator + "dsp-config";
            }
            logger.warn("DSPHOME：{}", DSPHOME);
        }

        if (StringHelper.isNullOrEmpty(DSPHOME_Parent)) {
            File dspHome = new File(DSPHOME);
            String homeParent = dspHome.getParent();

            if (StringHelper.isNullOrEmpty(homeParent)) {
                homeParent = DSPHOME;
            }
            DSPHOME_Parent = StringHelper.trimEnd(StringHelper.trimEnd(homeParent, "/"), "\\");
        }
    }

    /**
     * 是否以debug模式运行
     */
    public static boolean isRunDebugMode = false;

    public static LimitMsg limitMsg;//内存中记录最近10条
    public static StartLog startLog;//启动日志

    /**
     * 类反射map
     */
    public static JavaClassMap javaClassMap;

    /**
     * 管理web运行时的请求
     */
    public static RuntimeManager webRuntimeMngr;

    public static BankServer bankServer;
    private static Thread logTraceThread;
    public static LogTrace logTrace;
    public static boolean enableAsyncBankLog;//是否起用异步日志

    public static TaskCenter taskCenter;

    /**
     * 启动DSP银行接口服务
     *
     * @param p_isAsync 是否异步，true则异步启动
     */
    public static void startDspServer(boolean p_isAsync) throws Exception {
        if (startLog == null) {
            startLog = new StartLog();
        }
        if (limitMsg == null) {
            limitMsg = new LimitMsg();
        }
        startLog.addLog("开始启动dsp，系统版本：" + FgVersion.DspVersion);
        startLog.addLog("版本时间：" + FgVersion.LastUpdateTime);
        startLog.addLog("当前jdk版本：" + System.getProperty("java.version"));
        startLog.addLog("当前jvm版本" + System.getProperty("java.vm.name"));

        getInitInfo();
        startLog.addLogNoTime("系统默认字符集：" + Charset.defaultCharset());
        if (FGBiz.dspCenter == null) {
            startLog.addLogNoTime("程序主目录：" + DSPHOME);
            startLog.addLogNoTime("程序主目录的上级目录：" + DSPHOME_Parent);
            init(DSPHOME);//初始化系统运行的配置
        }

        if (FGBiz.dspCenter.dspSet.disableRetryPost == false) {
            startLog.addLogNoTime("sun.net.http.retryPost：false");
            System.setProperty("sun.net.http.retryPost", "false");
        }
        if (FGBiz.dspCenter.dspSet.enableProxy == true) {
            System.setProperty("http.proxyHost", FGBiz.dspCenter.dspSet.proxyIP);
            System.setProperty("http.proxyPort", FGBiz.dspCenter.dspSet.proxyPort);
            System.setProperty("https.proxyHost", FGBiz.dspCenter.dspSet.proxyIP);
            System.setProperty("https.proxyPort", FGBiz.dspCenter.dspSet.proxyPort);
            startLog.addLogNoTime("http.proxyHost：" + FGBiz.dspCenter.dspSet.proxyIP + ",http.proxyPort：" + FGBiz.dspCenter.dspSet.proxyPort);
        }

        //启动异步日志输出线程
        logTrace = new LogTrace(FGBiz.dspCenter.dspSet.logsMainDir);
        logTrace.addLogDir("bank", FGBiz.dspCenter.bankLogsDirPath + File.separator + FGBiz.dspCenter.bankLogsFirstDir);
        logTraceThread = new Thread(logTrace);
        logTraceThread.start();

        initLocalDb();//初始化本地数据库

        clusterCenter = new ClusterCenter();
        startLog.addLogNoTime("dsp cluster:" + clusterCenter.isEnable());

        enableAsyncBankLog = FGBiz.dspCenter.dspSet.enableAsyncBankLog;

        if (FGBiz.isRunDebugMode) {
            startLog.addLogNoTime("runMode：" + FGBiz.dspCenter.dspSet.runMode);
        }

        javaClassMap = new JavaClassMap();
        javaClassMap.load();

        webRuntimeMngr = new RuntimeManager();

        bankServer = new BankServer();
        tenantServer = new TenantServer();
        tenantClientServer = new TenantClientServer();

        taskCenter = new TaskCenter(FGBiz.dspCenter.dspSet);
        taskCenter.startScheduleTask();

        if (tenantClientServer.isEnable()) {
            bankServer.start(true);
            tenantClientServer.start();
        } else {
            bankServer.start(p_isAsync);
        }
    }

    private static TenantClientServer tenantClientServer;
    public static TenantServer tenantServer;

    public static void stopDspServer() {
        if (bankServer != null) {
            bankServer.stopDirect();
        }
        if (taskCenter != null) {
            taskCenter.stopScheduleTask();
        }
    }

    public static String stopDirectServer() {
        if (bankServer != null) {
            return bankServer.stopDirect();
        }
        return "";
    }

    public static String stopWebServer() {
        String stop1 = "";
        if (bankServer != null) {
            stop1 = bankServer.stopWeb();
        }
        String stop2 = logTrace.stop();
        return StringHelper.joinNotEmpty(stop1, stop2);
    }

    /**
     * 根据URID刷新前置缓存
     */
    public static String refreshBankFrontByURID(String[] p_URIDs) throws Exception {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < p_URIDs.length; i++) {
            sb.append(dspCenter.refreshBankFront("ByURID", p_URIDs[i]));
        }
        return StringHelper.trimEnd(sb.toString().trim(), "；") + "。";
    }

    /**
     * 根据Code刷新前置缓存
     */
    public static String refreshBankFrontByCode(String[] p_Codes) throws Exception {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < p_Codes.length; i++) {
            sb.append(dspCenter.refreshBankFront("ByCode", p_Codes[i]));
        }
        return StringHelper.trimEnd(sb.toString().trim(), "；") + "。";
    }

    /**
     * 刷新各直联渠道config配置文件
     */
    public static String refreshBankConfig(HashSet<String> bkCodes) {
        return DirectBase.refreshBankConfig(bkCodes);
    }

    /**
     * 刷新各直联渠道config配置文件
     */
    public static String refreshBankConfig(String[] p_bankCodes) {
        HashSet<String> hash = new HashSet<String>();
        for (int i = 0; i < p_bankCodes.length; i++) {
            if (!hash.contains(p_bankCodes[i])) {
                hash.add(p_bankCodes[i]);
            }
        }
        return DirectBase.refreshBankConfig(hash);
    }

    /**
     * 刷新DSPSystem配置文件
     */
    public static String refreshDSPSystem() throws Exception {
        return dspCenter.refreshDSPSystem();
    }
}
